#pragma once

#include "IEndPoint.h"
#include "PortIndex.h"
#include "IContractChecker.h"
#include "RoomMessage.h"
#include "SimpleEvent.h"
#include "SimpleCriticalSection.h"

namespace RoomFW {

//
// Class:	InvokeEndpoint
//
// Description:	Endpoint used for synchronous messaging.
//
// Author:	Andrew Sage
//
class InvokeEndpoint : public IEndPoint
{
public:

	//
	// Method:	InvokeEndpoint
	//
	// Description:	Constructor
	//
	// Parameters:
	//
	//	portIndex - Port index to receive messages for.
	//
	//	portIndex - Contract checker for portIndex.
	//
	InvokeEndpoint(PortIndex portIndex, IContractCheckerSPC protocol, const char* replyLog, const SimpleEvent& stopEvent = SimpleEvent());

	//
	// Method:	~InvokeEndpoint
	//
	// Description:	Destructor
	//
	~InvokeEndpoint(void);

	//
	// IEndpoint overrides.  Returns SMER_INVOKE_TIMEOUT if caller has abondoned wait.
	//
	virtual SendMessageError::Reason acceptMessage(
		MessageID messageID,
		IPayloadSP& payload,
		const char* senderName,
		IEndPointSP replyEndpoint = IEndPointSP());

	//
	// Method:	wait
	//
	// Description:	Wait for a reply message.
	//
	// Parameters:
	//
	//	timeout -	Time in milliseconds to wait.
	//
	// Return:	Reply message or null if timed out.
	//
	RoomMessageSP wait(DWORD timeout);

private:

	//
	// Port index to accept message for.
	//
	PortIndex portIndex_;

	//
	// Contract to check messages.
	//
	IContractCheckerSPC protocol_;

	//
	// String to log reply reciever object and port name.
	//
	std::string replyLog_;

	//
	// Reply message.
	//
	RoomMessageSP message_;

	//
	// Reply event.
	//
	SimpleEvent event_;

	//
	// Critical section for thread syncronization.
	//
	SimpleCriticalSection cs_;

	//
	// Caller's stop event.
	//
	SimpleEvent stopEvent_;

	//
	// Waiting flag.  Access must be syncronized.  Used to determine if
	// caller is still waiting.  Initialized to true because of the way this
	// is used in the ActiveObject.  It's always waited on, but it might
	// be be possible the reciever could reply before the wait is started.
	//
	bool isWaiting_;
};
typedef ::boost::shared_ptr<InvokeEndpoint> InvokeEndpointSP;

}
